#include <iostream>
#include <memory>
#include <string>
using namespace std;

// 简单工厂模式：
//  简单⼯⼚模式实现由⼀个⼯⼚对象通过类型决定创建出来指定产品类的实例。假设
//  有个⼯⼚能⽣产出⽔果，当客⼾需要产品的时候明确告知⼯⼚⽣产哪类⽔果，⼯⼚需要接收⽤⼾提
//  供的类别信息，当新增产品的时候，⼯⼚内部去添加新产品的⽣产⽅式。

// 缺点：
//  1. 所有东西⽣产在⼀起，产品太多会导致代码量庞⼤
//  2. 开闭原则遵循(开放拓展，关闭修改)的不是太好，要新增产品就必须修改⼯⼚⽅法。

// class Fruit
// {
// public:
//     // 纯虚函数
//     virtual void name() = 0;
// };

// class Apple : public Fruit
// {
// public:
//     void name() override
//     {
//         cout << "这是一个苹果" << endl;
//     }
// };

// class Banana : public Fruit
// {
// public:
//     void name() override
//     {
//         cout << "这是一个香蕉" << endl;
//     }
// };

// class FruitFactory
// {
// public:
//     static shared_ptr<Fruit> create(const std::string name)
//     {
//         if (name == "苹果")
//         {
//             return std::make_shared<Apple>();
//         }
//         else if (name == "香蕉")
//         {
//             return std::make_shared<Banana>();
//         }
//     }
// };

// int main()
// {
//     std::shared_ptr<Fruit> fruit = FruitFactory::create("苹果");
//     fruit->name();
//     fruit = FruitFactory::create("香蕉");
//     fruit->name();

//     return 0;
// }

// 工厂方法: ⼯⼚⽅法模式每次增加⼀个产品时，都需要增加⼀个具体产品类和⼯⼚类，这会使得系统中类的个数
//  成倍增加，在⼀定程度上增加了系统的耦合度。
// class FruitFactory
// {
// public:
//     virtual std::shared_ptr<Fruit> create() = 0;
// };

// class AppleFactory : public FruitFactory
// {
// public:
//     std::shared_ptr<Fruit> create() override
//     {
//         return std::make_shared<Apple>();
//     }
// };

// class BananaFactory : public FruitFactory
// {
// public:
//     std::shared_ptr<Fruit> create() override
//     {
//         return std::make_shared<Banana>();
//     }
// };

// int main()
// {
//     std::shared_ptr<FruitFactory> ff(new AppleFactory());
//     std::shared_ptr<Fruit> fruit = ff->create();
//     fruit->name();
//     ff.reset(new BananaFactory());
//     fruit = ff->create();
//     fruit->name();
//     return 0;
// }


// 抽象⼯⼚：围绕⼀个超级⼯⼚创建其他⼯⼚。每个⽣成的⼯⼚按照⼯⼚模式提供对象。
// 思想：将⼯⼚抽象成两层，抽象⼯⼚ & 具体⼯⼚⼦类， 在⼯⼚⼦类种⽣产不同类型的⼦产品
class Fruit
{
public:
    // 纯虚函数
    virtual void name() = 0;
};

class Apple : public Fruit
{
public:
    void name() override
    {
        cout << "这是一个苹果" << endl;
    }
};

class Banana : public Fruit
{
public:
    void name() override
    {
        cout << "这是一个香蕉" << endl;
    }
};

class Animal
{
public:
    // 纯虚函数
    virtual void name() = 0;
};

class Lamp : public Animal
{
public:
    void name() override
    {
        cout << "这是一个山羊" << endl;
    }
};

class Dog : public Animal
{
public:
    void name() override
    {
        cout << "这是一个小狗" << endl;
    }
};

class Factory
{
public:
    virtual std::shared_ptr<Fruit> getFruit(const std::string &name) = 0;
    virtual std::shared_ptr<Animal> getAnimal(const std::string &name) = 0;
};

class FruitFactory : public Factory
{
public:
    std::shared_ptr<Fruit> getFruit(const std::string &name) 
    {
        if (name == "苹果")
        {
            return std::make_shared<Apple>();
        }
        else
        {
            return std::make_shared<Banana>();
        }
    }

    std::shared_ptr<Animal> getAnimal(const std::string &name) 
    {
        return std::shared_ptr<Animal>();
    }
};

class AnimalFactory : public Factory
{
public:
    std::shared_ptr<Fruit> getFruit(const std::string &name)
    {
        return std::shared_ptr<Fruit>();
    }

    std::shared_ptr<Animal> getAnimal(const std::string &name)
    {
        if (name == "山羊")
        {
            return std::make_shared<Lamp>();
        }
        else
        {
            return std::make_shared<Dog>();
        }
    }
};


class FactoryProducer
{
public:
    static std::shared_ptr<Factory> getFactory(const std::string &name)
    {
        if (name == "动物")
        {
            return std::make_shared<AnimalFactory>();
        }
        else
        {
            return std::make_shared<FruitFactory>();
        }
    }
};

int main()
{

    std::shared_ptr<Factory> fruit_factory = FactoryProducer::getFactory("水果");
    std::shared_ptr<Fruit> fruit = fruit_factory->getFruit("苹果");
    fruit->name();
    fruit = fruit_factory->getFruit("香蕉");
    fruit->name();

    
    std::shared_ptr<Factory> animal_factory = FactoryProducer::getFactory("动物");
    std::shared_ptr<Animal> animal = animal_factory->getAnimal("山羊");
    animal->name();
    animal = animal_factory->getAnimal("小狗");
    animal->name();

    return 0;
}